package scut.carson_ho.searchview;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import ohos.data.DatabaseHelper;
import ohos.data.rdb.RdbPredicates;
import ohos.data.rdb.RdbStore;
import ohos.data.rdb.StoreConfig;
import ohos.data.resultset.ResultSet;
import ohos.multimodalinput.event.KeyEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class SearchView extends DirectionalLayout {

    private Context context;

    // 搜索框组件
    private TextField et_search; // 搜索按键
    private Image et_clear; //搜索清除按键
    private Text tv_clear;  // 删除搜索记录按键
    private DirectionalLayout search_block; // 搜索框布局
    private Image searchBack; // 返回按键

    // ListView列表 & 适配器
    private ListContainer listView;
    private SampleItemProvider provider;

    // 数据库变量
    // 用于存放历史搜索记录
    private DatabaseHelper helper;
    private RdbStore db;

    // 回调接口
    private  ICallBack mCallBack; // 搜索按键回调接口
    private  bCallBack bCallBack; // 返回按键回调接口

    // 自定义属性设置
    // 1. 搜索字体属性设置：大小、颜色 & 默认提示
    private int textSizeSearch;
    private Color textColorSearch;
    private String textHintSearch;

    // 2. 搜索框设置：高度 & 颜色
    private int searchBlockHeight;
    private Color searchBlockColor;

    /**
     * 构造函数
     * 作用：对搜索框进行初始化
     */
    public SearchView(Context context) {
        super(context);
    }

    public SearchView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        this.context = context;
        initAttrs(context, attrSet);
        init();
    }

    public SearchView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        this.context = context;
        initAttrs(context, attrSet);
        init();
    }

    /**
     * 关注a
     * 作用：初始化自定义属性
     */
    private void initAttrs(Context context, AttrSet attrs) {

        // 搜索框字体大小（fp）
        Optional<Attr> sv_textSizeSearch = attrs.getAttr("sv_textSizeSearch");
        textSizeSearch = sv_textSizeSearch.isPresent() ? sv_textSizeSearch.get().getDimensionValue() : 18;

        // 搜索框字体颜色（使用十六进制代码，如#333、#8e8e8e）
        Optional<Attr> sv_textColorSearch = attrs.getAttr("sv_textColorSearch"); // 默认颜色 = 灰色
        textColorSearch = sv_textColorSearch.isPresent() ? sv_textColorSearch.get().getColorValue() : new Color(0xff666666);

        // 搜索框提示内容（String）
        Optional<Attr> sv_textHintSearch = attrs.getAttr("sv_textHintSearch");
        textHintSearch = sv_textHintSearch.isPresent() ? sv_textHintSearch.get().getStringValue() : "请输入关键字";

        // 搜索框高度
        Optional<Attr> sv_searchBlockHeight = attrs.getAttr("sv_searchBlockHeight");
        searchBlockHeight = sv_searchBlockHeight.isPresent() ? sv_searchBlockHeight.get().getDimensionValue() : 168;

        // 搜索框颜色
        Optional<Attr> sv_searchBlockColor = attrs.getAttr("sv_searchBlockColor");
        searchBlockColor = sv_searchBlockColor.isPresent() ? sv_searchBlockColor.get().getColorValue() : new Color(0xffffffff); // 默认颜色 = 白色
    }

    /**
     * 关注b
     * 作用：初始化搜索框
     */
    private void init() {
        // 1. 初始化UI组件->>关注c
        initView();

        // 2. 实例化数据库SQLiteOpenHelper子类对象
        helper = new DatabaseHelper(getContext());

        // 3. 第1次进入时查询所有的历史搜索记录
        queryData("");

        /**
         * "清空搜索历史"按钮
         */
        tv_clear.setClickedListener(component -> {
            // 清空数据库->>关注2
            deleteData();
            // 模糊搜索空字符 = 显示所有的搜索历史（此时是没有搜索记录的）
            queryData("");
        });

        /**
         * 监听输入键盘更换后的搜索按键
         * 调用时刻：点击键盘上的搜索键时
         */
        et_search.setKeyEventListener((component, keyEvent) -> {

            if (keyEvent.getKeyCode() == KeyEvent.KEY_ENTER && keyEvent.isKeyDown()) {

                // 1. 点击搜索按键后，根据输入的搜索字段进行查询
                // 注：由于此处需求会根据自身情况不同而不同，所以具体逻辑由开发者自己实现，此处仅留出接口
                if (!(mCallBack == null)){
                    mCallBack.SearchAciton(et_search.getText());
                }

                // 2. 点击搜索键后，对该搜索字段在数据库是否存在进行检查（查询）->> 关注1
                boolean hasData = hasData(et_search.getText().trim());

                // 3. 若存在，则不保存；若不存在，则将该搜索字段保存（插入）到数据库，并作为历史搜索记录
                if (!hasData) {
                    insertData(et_search.getText().trim());
                    queryData("");
                }

            }
            return false;
        });

        et_search.setEditorActionListener(new Text.EditorActionListener() {

            @Override
            public boolean onTextEditorAction(int i) {
                // 1. 点击搜索按键后，根据输入的搜索字段进行查询
                // 注：由于此处需求会根据自身情况不同而不同，所以具体逻辑由开发者自己实现，此处仅留出接口
                if (!(mCallBack == null)){
                    mCallBack.SearchAciton(et_search.getText());
                }

                // 2. 点击搜索键后，对该搜索字段在数据库是否存在进行检查（查询）->> 关注1
                boolean hasData = hasData(et_search.getText().trim());

                // 3. 若存在，则不保存；若不存在，则将该搜索字段保存（插入）到数据库，并作为历史搜索记录
                if (!hasData) {
                    insertData(et_search.getText().trim());
                    queryData("");
                }
                return false;
            }
        });

        /**
         * 搜索框的文本变化实时监听
         */
        et_search.addTextObserver(new Text.TextObserver() {
            @Override
            public void onTextUpdated(String s, int i, int i1, int i2) {
                // 每次输入后，模糊查询数据库 & 显示
                // 注：若搜索框为空,则模糊搜索空字符 = 显示所有的搜索历史
                String tempName = et_search.getText();
                queryData(tempName); // ->>关注1

                if (tempName == null || tempName.equals("")) {
                    et_clear.setVisibility(INVISIBLE);
                } else {
                    et_clear.setVisibility(VISIBLE);
                }
            }
        });

        et_clear.setClickedListener(component -> et_search.setText(""));

        /**
         * 搜索记录列表（ListView）监听
         * 即当用户点击搜索历史里的字段后,会直接将结果当作搜索字段进行搜索
         */
        listView.setItemClickedListener((listContainer, component, i, l) -> {
            // 获取用户点击列表里的文字,并自动填充到搜索框内
            Text text = (Text) component.findComponentById(ResourceTable.Id_item_index);
            String name = text.getText();
            et_search.setText(name);
        });

        /**
         * 点击返回按键后的事件
         */
        searchBack.setClickedListener(component -> {
            // 注：由于返回需求会根据自身情况不同而不同，所以具体逻辑由开发者自己实现，此处仅留出接口
            if (!(bCallBack == null)){
                bCallBack.BackAciton();
            }

            //根据输入的内容模糊查询商品，并跳转到另一个界面，这个根据需求实现
            new ToastDialog(context)
                    .setText("返回到上一页")
                    .setAlignment(LayoutAlignment.CENTER)
                    .show();
        });
    }

    /**
     * 关注c：绑定搜索框xml视图
     */
    private void initView() {
        // 1. 绑定R.layout.search_layout作为搜索框的xml文件
        LayoutScatter.getInstance(this.context).parse(ResourceTable.Layout_search_layout, this, true);

        // 2. 绑定搜索框EditText
        et_search = (TextField) findComponentById(ResourceTable.Id_et_search);
        et_search.setTextSize(textSizeSearch, Text.TextSizeType.FP);
        et_search.setTextColor(textColorSearch);
        et_search.setHint(textHintSearch);
        et_search.setHintColor(new Color(0xffbfbfbf));
        et_search.setBubbleSize(0, 0);

        et_clear = (Image)findComponentById(ResourceTable.Id_et_clear);
        if (et_search.getText() == null || et_search.getText().equals("")) {
            et_clear.setVisibility(INVISIBLE);
        } else {
            et_clear.setVisibility(VISIBLE);
        }

        // 3. 搜索框背景颜色
        search_block = (DirectionalLayout)findComponentById(ResourceTable.Id_search_block);
        search_block.setHeight(searchBlockHeight);
        ShapeElement background = new ShapeElement();
        background.setRgbColor(new RgbColor(searchBlockColor.getValue()));
        search_block.setBackground(background);

        // 4. 历史搜索记录 = ListView显示
        listView = (ListContainer) findComponentById(ResourceTable.Id_listView);

        // 5. 删除历史搜索记录 按钮
        tv_clear = (Text) findComponentById(ResourceTable.Id_tv_clear);
        tv_clear.setVisibility(HIDE);

        // 6. 返回按键
        searchBack = (Image) findComponentById(ResourceTable.Id_search_back);
    }

    /**
     * 关注1
     * 模糊查询数据 & 显示到ListView列表上
     */
    private void queryData(String tempName) {
        // 1. 模糊搜索
        RdbPredicates predicates = new RdbPredicates("records");
        predicates.like("name", "%" + tempName + "%");
        predicates.orderByDesc("id");
        ResultSet resultSet = getRdbStore().query(predicates, null);

        List<String> items = new ArrayList<String>();
        while (resultSet.goToNextRow()) {
            Integer idx = resultSet.getColumnIndexForName("name");
            items.add(resultSet.getString(idx));
        }
        // 2. 创建adapter适配器对象 & 装入模糊搜索的结果
        provider = new SampleItemProvider(items, getContext());
        // 3. 设置适配器
        listView.setItemProvider(provider);

        // 当输入框为空 & 数据库中有搜索记录时，显示 "删除搜索记录"按钮
        if (tempName.equals("") && items.size() != 0) {
            tv_clear.setVisibility(VISIBLE);
        } else {
            tv_clear.setVisibility(HIDE);
        }
    }

    /**
     * 关注2：清空数据库
     */
    private void deleteData() {
        db = getRdbStore();
        db.executeSql("delete from records");
        db.close();
        tv_clear.setVisibility(HIDE);
    }

    /**
     * 关注3
     * 检查数据库中是否已经有该搜索记录
     */
    private boolean hasData(String tempName) {
        // 从数据库中Record表里找到name=tempName的id
        RdbPredicates predicates = new RdbPredicates("records");
        predicates.equalTo("name", tempName);
        ResultSet resultSet = getRdbStore().query(predicates, new String[]{"id", "name"});
        //  判断是否有下一个
        return resultSet.goToNextRow();
    }

    /**
     * 关注4
     * 插入数据到数据库，即写入搜索字段到历史搜索记录
     */
    private void insertData(String tempName) {
        db = getRdbStore();
        db.executeSql("insert into records(name) values('" + tempName + "')");
        db.close();
    }

    private RdbStore getRdbStore() {
        return helper.getRdbStore(StoreConfig.newDefaultConfig("temp.db"), 1, new RecordSQLiteOpenCallback(), null);
    }

    /**
     * setTextSizeSearch: 设置字体大小
     * @param textSize
     */
    public void setTextSizeSearch(int textSize) {
        textSizeSearch = textSize;
        et_search.setTextSize(textSizeSearch, Text.TextSizeType.FP);
    }

    /**
     * setTextColorSearch: 设置字体颜色
     * @param textColor
     */
    public void setTextColorSearch(Color textColor) {
        textColorSearch = textColor;
        et_search.setTextColor(textColorSearch);
    }

    /**
     * setTextHintSearch: 设置提示内容
     * @param textHint
     */
    public void setTextHintSearch(String textHint) {
        textHintSearch = textHint;
        et_search.setHint(textHintSearch);
    }

    /**
     * setTextSizeSearch: 设置高度
     * @param textHint
     */
    public void setSearchBlockHeight(String textHint) {
        textHintSearch = textHint;
        search_block.setHeight(searchBlockHeight);
    }

    /**
     * setTextColorSearch: 设置背景颜色
     * @param bgColor
     */
    public void setSearchBlockColor(Color bgColor) {
        searchBlockColor = bgColor;
        ShapeElement background = new ShapeElement();
        background.setRgbColor(new RgbColor(searchBlockColor.getValue()));
    }

    /**
     * 点击键盘中搜索键后的操作，用于接口回调
     */
    public void setOnClickSearch(ICallBack mCallBack){
        this.mCallBack = mCallBack;
    }

    /**
     * 点击返回后的操作，用于接口回调
     */
    public void setOnClickBack(bCallBack bCallBack) {
        this.bCallBack = bCallBack;
    }

}
